package tp3;

import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Scanner;
import java.io.FileOutputStream;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;

public class Servidor implements IServidorCinema {

    private BancoFilmes bancoFilmes = new BancoFilmes();

    /* Variaveis usadas na marcacao dos tempos */
    private static final String ARQ_TEMPOS = "tempos_servidor.csv";
    private static final int MAX_CLIENTES = 5;
    private static final int MAX_PEDIDOS = 105;
    private int[] posClientes = new int[MAX_CLIENTES];
    private float[][] tempos = new float[MAX_CLIENTES][MAX_PEDIDOS];

    public Servidor() {
        for(int i=0; i<MAX_CLIENTES; i++){
            posClientes[i] = 0;
        }
    }

    public String[] recuperarTitulos(byte idCliente){
        System.err.println("passei 1");
        long tempo = -System.nanoTime();
        String[] titulos = bancoFilmes.recuperarTitulos();
        tempo += System.nanoTime();
        tempos[idCliente][posClientes[idCliente]++] = ((float)tempo)/1000000000;
        return titulos;
    }
    /* Retorna a sinopse de um filme dado seu id */
    public String recuperarSinopseFilme(int id, byte idCliente){
        System.err.println("passei 2");
        long tempo = -System.nanoTime();
        String sinopse = bancoFilmes.recuperarSinopseFilme(id);
        tempo += System.nanoTime();
        tempos[idCliente][posClientes[idCliente]++] = ((float)tempo)/1000000000;
        return sinopse;
    }
    /* Retorna todas as informacoes de um filme dado seu id */
    public Filme recuperarInformacoesFilme(int id, byte idCliente){
        System.err.println("passei 3");
        long tempo = -System.nanoTime();
        Filme filme = bancoFilmes.recuperarInformacoesFilme(id);
        tempo += System.nanoTime();
        tempos[idCliente][posClientes[idCliente]++] = ((float)tempo)/1000000000;
        return filme;
    }
    /* Retorna todas as informacoes de todos os filmes */
    public Filme[] recuperarTudo(byte idCliente){
        System.err.println("passei 4");
        long tempo = -System.nanoTime();
        Filme [] filmes = bancoFilmes.recuperarTudo();
        tempo += System.nanoTime();
        tempos[idCliente][posClientes[idCliente]++] = ((float)tempo)/1000000000;
        return filmes;
    }
    /* Da nota para um filme */
    public int darNotaFilme(int id, int nota, byte idCliente){
        System.err.println("passei 5");
        long tempo = -System.nanoTime();
        int novaNota = bancoFilmes.darNotaFilme(id, nota);
        tempo += System.nanoTime();
        tempos[idCliente][posClientes[idCliente]++] = ((float)tempo)/1000000000;
        return novaNota;
    }
    /* Retorna a nota e o numero de clientes que deram nota a um filme */
    public Pair<Integer, Integer> recuperarNotaFilme(int id, byte idCliente){
        System.err.println("passei 6");
        long tempo = -System.nanoTime();
        Pair<Integer, Integer> p = bancoFilmes.recuperarNotaFilme(id);
        tempo += System.nanoTime();
        tempos[idCliente][posClientes[idCliente]++] = ((float)tempo)/1000000000;
        return p;
    }

    /* Grava os tempos marcados em um arquivo csv */
    public void gravarTempos() throws Exception{
        BufferedWriter br = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(ARQ_TEMPOS)));
        for(int i=0; i<MAX_PEDIDOS; i++){
            for(int j=0; j<MAX_CLIENTES; j++){
                if(posClientes[j]>0)
                    br.write(tempos[j][i]+";");
            }
            br.write("\n");
        }
        br.close();
    }

    public static void main(String args[]) {
        /* Instala SecurityManager */
        /*if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }*/
	try {
            /* Cria novo objeto Servidor e exporta */
	    Servidor servidor = new Servidor();
	    IServidorCinema stub = (IServidorCinema)UnicastRemoteObject.exportObject(servidor, 50000);

	    /* Faz o bind the do stub do objeto remoto no registro */
	    Registry registry = LocateRegistry.createRegistry(51099);
	    registry.rebind("ServidorFilmes", stub);

            /* Carrega o banco de dados na memoria */
            servidor.bancoFilmes.carregarBanco(BancoFilmes.ARQ_BANCO);

	    System.out.println("Servidor pronto");

            /* Executa servidor ate que alguem aperte enter */
            Scanner scan = new Scanner(System.in).useDelimiter("\n");
            scan.next();
            scan.close();

            /* Salva o banco de dados */
            servidor.bancoFilmes.salvarBanco(BancoFilmes.ARQ_BANCO);

            /* Salva os tempos marcados */
            try{
                servidor.gravarTempos();
            }catch(Exception e){
                System.err.println("Erro ao gravar os tempos: " + e.toString());
                e.printStackTrace();
            }

            /* Remove o objeto exportado */
            registry.unbind("ServidorFilmes");
            UnicastRemoteObject.unexportObject(servidor, true);
            return;
	} catch (Exception e) {
	    System.err.println("Excecao no servidor: " + e.toString());
	    e.printStackTrace();
	}
    }

}
